package com.wy.sloth.core;

import java.util.Calendar;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

import com.wy.sloth.config.SlothConfig;
import com.wy.sloth.exception.SlothException;
import com.wy.sloth.redis.lock.LockCallbackHandler;
import com.wy.sloth.redis.lock.RedisLockTemplate;
import com.wy.sloth.redis.service.SlothRedisService;
import com.wy.sloth.util.StringUtils;

import lombok.Getter;
import lombok.Setter;

/**
 * 日志管理器
 * 
 * @author wangyuan
 * @since 2019年3月8日
 */
public class SlothMsgLogManager {
    
    private static final Logger logger = LoggerFactory.getLogger(SlothMsgLogManager.class);
    
    /**
     * 日志清除任务运行时间间隔24小时
     */
    private static final long PERIOD = 24 * 60 * 60 * 1000L;

    /**
     * 线程池
     */
    private ScheduledExecutorService logExecutor;
    
    @Getter
    @Setter
    private SlothRedisService slothRedisService;
    
    @Getter
    @Setter
    private SlothConfig slothConfig;
    
    private SlothNameManager slothNameManager;
    
    private ValueOperations<String, String> valueOperations;
    
    private RedisLockTemplate redisLockTemplate;
    
    /**
     * 标志本管理器是否启动工作
     */
    private volatile boolean workerCreated = false;
    
    public SlothMsgLogManager(RedisTemplate<String, String> stringRedisTemplate, 
    		SlothRedisService slothRedisService, 
    		SlothConfig slothConfig, 
    		SlothNameManager slothNameManager) {
        super();
        this.slothRedisService = slothRedisService;
        this.slothConfig = slothConfig;
        this.valueOperations = stringRedisTemplate.opsForValue();
        this.slothNameManager = slothNameManager;
        this.redisLockTemplate = new RedisLockTemplate(this.slothConfig, stringRedisTemplate);
    }
    
    public void start() {
        logger.info("-----消息日志管理器准备启动-----");
        
        String clearLogWorkerFlagKey = slothNameManager.getClearLogWorkerFlagKey();
        
        workerCreated = redisLockTemplate.execute(clearLogWorkerFlagKey, new LockCallbackHandler<Boolean>() {

            @Override
            public Boolean doInLock() throws SlothException {
                boolean result = false;
                String clearWorkerFlag = valueOperations.get(clearLogWorkerFlagKey);
                if(StringUtils.isEmpty(clearWorkerFlag) || "0".equals(clearWorkerFlag)){
                    valueOperations.set(clearLogWorkerFlagKey, "1");
                    result = true;
                } else {
                    result = false;
                }
                
                return result;
            }
        });
        
        if(!workerCreated){
            logger.info("-----已存在消息日志管理器，本次将不启动此管理器，退出启动方法-----");
            return;
        }
        
        logExecutor = Executors.newSingleThreadScheduledExecutor();
        
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        long initialDelay = calendar.getTimeInMillis();
        
        logExecutor.scheduleAtFixedRate(new ClearMsgLogWorker(), initialDelay - System.currentTimeMillis(), PERIOD, TimeUnit.MILLISECONDS);
        //logExecutor.scheduleAtFixedRate(new ClearMsgLogWorker(), 10 * 1000L, PERIOD, TimeUnit.MILLISECONDS);
        logger.info("-----消息日志管理器结束启动-----");
    }
    
    public void destroy() {
        logger.info("-----消息日志管理器准备终止-----");
        if(workerCreated){
            String clearLogWorkerFlagKey = slothNameManager.getClearLogWorkerFlagKey();
            
            workerCreated = redisLockTemplate.execute(clearLogWorkerFlagKey, new LockCallbackHandler<Boolean>() {

                @Override
                public Boolean doInLock() throws SlothException {
                    String clearWorkerFlag = valueOperations.get(clearLogWorkerFlagKey);
                    if(StringUtils.isEmpty(clearWorkerFlag) || "1".equals(clearWorkerFlag)){
                        valueOperations.set(clearLogWorkerFlagKey, "0");
                    }
                    
                    return null;
                }
            });
            
            if(!logExecutor.isShutdown()){
                logExecutor.shutdown();
            }
        }
        logger.info("-----消息日志管理器结束终止-----");
    }
    
    @Override
    protected void finalize() throws Throwable {
        if(!logExecutor.isShutdown()){
            logExecutor.shutdown();
        }
        super.finalize();
    }
    
    class ClearMsgLogWorker implements Runnable {

        @Override
        public void run() {
            logger.info("-----消息日志清理线程开始工作-----");
            try {
                //计算保留日志最小开始时间的时间戳
                int maxDay = slothConfig.getMsgLogSaveMaxDay();
                Calendar calendar = Calendar.getInstance();
                calendar.add(Calendar.DAY_OF_MONTH, -maxDay);
                calendar.set(Calendar.HOUR_OF_DAY, 0);
                calendar.set(Calendar.MINUTE, 0);
                calendar.set(Calendar.SECOND, 0);
                calendar.set(Calendar.MILLISECOND, 0);
                long earlyTempStamp = calendar.getTimeInMillis();
                
                slothRedisService.clearEarlyMsgLog(earlyTempStamp);
            } catch (Exception e) {
                logger.error("清除早期消息日志时出现错误，原因是：", e);
            }
            logger.info("-----消息日志清理线程结束工作-----");
        }
    }
}
